package fi.profecons.csswindows;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.Rectangle;
import java.rmi.server.ObjID;
import java.util.HashMap;
import java.util.Map;

import fi.profecons.csswindows.toolkit.Menu;

/**
 * Base class for all user interface elements.
 * 
 * @author ProfeCons Oy - Semi Arajuuri
 *
 */

public class Element extends ScriptCache{
	
	/**
	 * Element will be placed absolutely when inside a container.
	 */
	public final static String POSITION_ABSOLUTE = "absolute";
	/**
	 * Element will be placed relatively when inside a container.
	 */
	public final static String POSITION_RELATIVE = "relative";
	/**
	 * Element will be placed statically when inside a container.
	 */
	public final static String POSITION_STATIC = "static";

	private ObjID id;

	private Point location;

	private Dimension size;

	private Dimension preferredSize;

	private ActionListener actionListener;

	private Element parent = null;

	private Menu contextMenu = null;

	private String action = null;

	private Map actions = new HashMap();
	
	private Object object = null;

	public Element() {
		this.id = new ObjID();
		this.size = new Dimension(0, 0);
		this.location = new Point(0, 0);
		this.preferredSize = new Dimension(0, 0);
	}

	/**
	 * Set action listener for this element. Default action listener does nothing, so you must
	 * create one your self (if needed).
	 * @param listener Action listener for this element.
	 */
	public void setActionListener(ActionListener listener) {
		this.actionListener = listener;
	}

	/**
	 * Retrieve the current action listener.
	 * @return Current action listener.
	 */
	public ActionListener getActionListener() {
		return this.actionListener;
	}
	/**
	 * Get the generated unique identifier for this element. 
	 * @return Unique identifier.
	 */
	public String getId() {
		return "e" + id.hashCode();
	}
	/**
	 * Display this element inside its container. By default all elements are hidden.
	 */
	public void show() {
		addCommand("getElement('" + getId() + "').show();");
		this.refresh();
	}
	/**
	 * Hide this element.
	 */
	public void hide() {
		addCommand("getElement('" + getId() + "').hide();");
	}
	
	public void setX(int x) {
		this.location.x = x;
		addCommand("getElement('" + getId() + "').setX(" + x + ");");
	}

	public int getY() {
		return this.location.y;
	}

	public void setY(int y) {
		this.location.y = y;
		addCommand("getElement('" + getId() + "').setY(" + y + ");");
	}

	public int getHeight() {
		return this.size.height;
	}

	public void setHeight(int height) {
		this.size.height = height;
		addCommand("getElement('" + getId() + "').setHeight(" + height + ");");
	}

	public int getWidth() {
		return this.size.width;
	}

	protected void setState(State state) {
		if (this.contextMenu != null && state != null) {
			state.add(this.contextMenu);
		}
		super.setState(state);
	}

	public void setWidth(int width) {
		this.size.width = width;
		addCommand("getElement('" + getId() + "').setWidth(" + width + ");");
	}

	public Point getLocation() {
		return location;
	}

	public void setLocation(Point location) {
		this.location = location;
	}

	public void setBounds(int x, int y, int width, int height) {
		setSize(width, height);
		setLocation(x, y);
	}

	public void setSize(int width, int height) {
		this.size.width = width;
		this.size.height = height;
		addCommand("getElement('" + getId() + "').setSize(" + width + ", "
				+ height + ");");
	}

	public void setLocation(int x, int y) {
		setX(x);
		setY(y);
	}

	public void setBounds(Rectangle r) {
		setBounds(r.x, r.y, r.width, r.height);
	}

	public void setSize(Dimension d) {
		setSize(d.width, d.height);
	}

	public Element getParent() {
		return this.parent;
	}

	public void setParent(Element e) {
		this.parent = e;
	}

	public Dimension getPreferredSize() {
		return this.preferredSize;
	}

	public void setPreferredSize(int width, int height) {
		this.preferredSize.width = width;
		this.preferredSize.height = height;

	}

	public void setPreferredSize(Dimension d) {
		this.preferredSize = d;

	}

	public Rectangle getBounds() {
		return new Rectangle(this.location.x, this.location.y, this.size.width,
				this.size.height);
	}

	public Dimension getSize() {
		return this.size;
	}

	public int getX() {
		return this.location.x;
	}

	public Element getElement(String id) {
		if (getId().equals(id)) {
			return this;
		}
		return null;
	}

	public void setBgColor(Color c) {
		addCommand("getElement('" + getId() + "').setBgColor(" + c.getRed()
				+ ", " + c.getGreen() + ", " + c.getBlue() + ");");

	}

	public void setFgColor(Color c) {
		addCommand("getElement('" + getId() + "').setFgColor(" + c.getRed()
				+ ", " + c.getGreen() + ", " + c.getBlue() + ");");

	}

	public void setPosition(String mode) {
		addCommand("getElement('" + getId() + "').setPosition('" + mode + "');");
	}

	public void refresh() {

	}

	public void setContextMenu(Menu menu) {
		addCommand("getElement('" + getId() + "').setContextMenu(getElement('"
				+ menu.getId() + "'));");
		this.contextMenu = menu;
	}

	public void setAction(String action) {
		addCommand("getElement('" + getId() + "').setAction('" + action + "');");
		this.action = action;
	}

	public void setAction(String action, String type) {
		addCommand("getElement('" + getId() + "').setAction('" + action
				+ "', '" + type + "');");
		this.actions.put(type, action);
	}

	public String getAction() {
		return this.action;
	}

	public void setBgTransparent() {
		addCommand("getElement('" + getId() + "').setBgTransparent();");

	}

	public void setOpacity(float f) {
		addCommand("getElement('" + getId() + "').setOpacity(" + f + ");");
	}

	public void setDragging(boolean enabled) {
		if (enabled) {
			addCommand("getElement('" + getId() + "').enableDrag();");
		} else {
			addCommand("getElement('" + getId() + "').disableDrag();");
		}
	}

	public void setAsDropTarget(boolean dropTarget) {
		if(dropTarget) {
			addCommand("getElement('" + getId() + "').setAsDropTarget(true);");
		}else{
			addCommand("getElement('" + getId() + "').setAsDropTarget(false);");
		}
		
	}

	public void focus() {
		addCommand("getElement('" + getId() + "').focus();");
	}

	public void fadeIn(int milliseconds) {
		addCommand("getElement('" + getId() + "').fadeIn(" + milliseconds+ ");");
	}

	public void fadeOut(int milliseconds) {
		addCommand("getElement('" + getId() + "').fadeOut(" + milliseconds+ ");");
	}

	/**
	 * Get the attached object.
	 * @return
	 */
	public Object getObject() {
		return object;
	}

	/**
	 * Attach a object into this element. You can for example attach an object from your model.
	 * @param object
	 */
	public void setObject(Object object) {
		this.object = object;
	}

}
